package com.lambkit.db.datasource;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.symmetric.AES;
import com.lambkit.db.LambkitPasswordCracker;

import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class DataSourcePasswordCracker implements LambkitPasswordCracker {

	/**
	 * 16字节
	 */
	private static final String IV_KEY = "0000000000000000";

	private static int maxLength = 24;

	@Override
	public String encode(String password, String salt) {

		if(StrUtil.isBlank(password)) {
			return password;
		}
		if(StrUtil.isBlank(salt)) {
			return encryptFromString(password, "lambkit@", Mode.CBC, Padding.ZeroPadding);
		} else {
			return encryptFromString(password, salt, Mode.CBC, Padding.ZeroPadding);
		}
	}

	@Override
	public String decode(String password, String salt) {

		if(StrUtil.isBlank(password) || password.length() < maxLength) {
			return password;
		}
		if(StrUtil.isBlank(salt)) {
			return decryptFromString(password, "lambkit@", Mode.CBC, Padding.ZeroPadding);
		} else {
			return decryptFromString(password, salt, Mode.CBC, Padding.ZeroPadding);
		}
	}

	public static String encryptFromString(String data, String salt, Mode mode, Padding padding) {
		String encodeKey = DigestUtil.md5Hex16(salt);
		AES aes;
		if (Mode.CBC == mode) {
			aes = new AES(mode, padding,
					new SecretKeySpec(encodeKey.getBytes(), "AES"),
					new IvParameterSpec(IV_KEY.getBytes()));
		} else {
			aes = new AES(mode, padding,
					new SecretKeySpec(encodeKey.getBytes(), "AES"));
		}
		return aes.encryptBase64(data, StandardCharsets.UTF_8);
	}

	public static String decryptFromString(String data, String salt, Mode mode, Padding padding) {
		String encodeKey = DigestUtil.md5Hex16(salt);
		AES aes;
		if (Mode.CBC == mode) {
			aes = new AES(mode, padding,
					new SecretKeySpec(encodeKey.getBytes(), "AES"),
					new IvParameterSpec(IV_KEY.getBytes()));
		} else {
			aes = new AES(mode, padding,
					new SecretKeySpec(encodeKey.getBytes(), "AES"));
		}
		byte[] decryptDataBase64 = aes.decrypt(data);
		return new String(decryptDataBase64, StandardCharsets.UTF_8);
	}
}
